#include "serve-helper.h"
#include "ns3/serve-frame.h"
#include "ns3/ipv4.h"
#include "ns3/uinteger.h"
#include "ns3/names.h"
#include "ns3/loopback-net-device.h"
#include "ns3/traffic-control-layer.h"
#include "ns3/traffic-control-helper.h"
#include "ns3/net-device-queue-interface.h"
#include "ns3/log.h"

namespace ns3{

NS_LOG_COMPONENT_DEFINE ("ServeHelper");

ServeHelper::ServeHelper()
{
    m_Factory.SetTypeId(ServeFrame::GetTypeId());
}

void ServeHelper::SetServeAttribute(std::string name, const AttributeValue &value)
{
    m_Factory.Set(name, value);
}


ApplicationContainer ServeHelper::InstallServe (Ptr<NetDevice> netDevice) const
{
  return ApplicationContainer (InstallServePriv (netDevice));
}

// 给所有网卡安装应用
ApplicationContainer ServeHelper::InstallServe (NetDeviceContainer netDevices) const
{
    // 返回值的容器
    ApplicationContainer apps;
    // 遍历每一个网卡安装应用
    for (NetDeviceContainer::Iterator i = netDevices.Begin (); i != netDevices.End (); ++i)
    {
        apps.Add (InstallServePriv (*i));
    }
    return apps;
}   


// 给一个网卡安装应用
Ptr<Application> ServeHelper::InstallServePriv(Ptr<NetDevice> netDevice) const
{
    Ptr<Node> node = netDevice->GetNode();
    NS_ASSERT_MSG (node != 0, "ServeHelper: NetDevice is not not associated with any node -> fail");

    Ptr<Ipv4> ipv4 = node->GetObject<Ipv4> ();
    NS_ASSERT_MSG (ipv4, "ServeHelper: NetDevice is associated"
                   " with a node without IPv4 stack installed -> fail "
                   "(maybe need to use InternetStackHelper?)");

    // 这个函数调用中用到了find 猜想是不是实现了判断可用的功能
    int32_t interface = ipv4->GetInterfaceForDevice (netDevice);
    if(interface == -1)
    {
        interface = ipv4->AddInterface(netDevice);
    }
    NS_ASSERT_MSG(interface >= 0, "ServeHelper: Interface index not found" );

    // 路由的一些参数设置
    ipv4->SetMetric (interface, 1);
    ipv4->SetUp(interface);


    // 安装默认的流量控制程序
    Ptr<TrafficControlLayer> tc = node->GetObject<TrafficControlLayer> ();
    if (tc && DynamicCast<LoopbackNetDevice> (netDevice) == 0 && tc->GetRootQueueDiscOnDevice (netDevice) == 0)
    {
        Ptr<NetDeviceQueueInterface> ndqi = netDevice->GetObject<NetDeviceQueueInterface> ();
        // It is useless to install a queue disc if the device has no
        // NetDeviceQueueInterface attached: the device queue is never
        // stopped and every packet enqueued in the queue disc is
        // immediately dequeued, hence there will never be backlog
        if (ndqi)
        {
            std::size_t nTxQueues = ndqi->GetNTxQueues ();
            NS_LOG_LOGIC ("ServeHelper - Installing default traffic control configuration ("
                            << nTxQueues << " device queue(s))");
            TrafficControlHelper tcHelper = TrafficControlHelper::Default (nTxQueues);
            tcHelper.Install (netDevice);
        }
    }

    Ptr<ServeFrame> app = DynamicCast <ServeFrame> (m_Factory.Create<ServeFrame> ());
    app->SetServeNetDevice (netDevice);
    node->AddApplication (app);

    return app;
}




Ipv4InterfaceContainer ServeHelper::InstallFixedAddress(Ptr<NetDevice> netDevice, Ipv4Address addr, Ipv4Mask mask)
{
    Ipv4InterfaceContainer retval;

    Ptr<Node> node = netDevice->GetNode();
    NS_ASSERT_MSG (node != 0, "ServeHelper: NetDevice is not not associated with any node -> fail");

    Ptr<Ipv4> ipv4 = node->GetObject<Ipv4> ();
    NS_ASSERT_MSG (ipv4, "ServeHelper: NetDevice is associated"
                    " with a node without IPv4 stack installed -> fail "
                    "(maybe need to use InternetStackHelper?)");

    int32_t interface = ipv4->GetInterfaceForDevice (netDevice);
    if (interface == -1)
    {
      interface = ipv4->AddInterface (netDevice);
    }
    NS_ASSERT_MSG (interface >= 0, "ServeHelper: Interface index not found");

    Ipv4InterfaceAddress ipv4Addr = Ipv4InterfaceAddress (addr, mask);
    ipv4->AddAddress (interface, ipv4Addr);
    ipv4->SetMetric (interface, 1);
    ipv4->SetUp (interface);
    retval.Add (ipv4, interface);

    // 安装默认的流量控制程序 
    // Install the default traffic control configuration if the traffic
    // control layer has been aggregated, if this is not
    // a loopback interface, and there is no queue disc installed already
    Ptr<TrafficControlLayer> tc = node->GetObject<TrafficControlLayer> ();
    if (tc && DynamicCast<LoopbackNetDevice> (netDevice) == 0 && tc->GetRootQueueDiscOnDevice (netDevice) == 0)
        {
        Ptr<NetDeviceQueueInterface> ndqi = netDevice->GetObject<NetDeviceQueueInterface> ();
        // It is useless to install a queue disc if the device has no
        // NetDeviceQueueInterface attached: the device queue is never
        // stopped and every packet enqueued in the queue disc is
        // immediately dequeued, hence there will never be backlog
        if (ndqi)
            {
            std::size_t nTxQueues = ndqi->GetNTxQueues ();
            NS_LOG_LOGIC ("ServeHelper - Installing default traffic control configuration ("
                            << nTxQueues << " device queue(s))");
            TrafficControlHelper tcHelper = TrafficControlHelper::Default (nTxQueues);
            tcHelper.Install (netDevice);
            }
        }

    // check that the already fixed addresses are not in conflict with the pool
    std::list<std::pair<Ipv4Address, Ipv4Address> >::iterator iter;
    for (iter=m_addressPools.begin (); iter!=m_addressPools.end (); iter ++)
        {
        if (addr.Get () >= iter->first.Get () && addr.Get () <= iter->second.Get ())
            {
            NS_ABORT_MSG ("DhcpHelper: Fixed address can not conflict with a pool: " << addr << " is in [" << iter->first << ",  " << iter->second << "]");
            }
        }
    m_fixedAddresses.push_back (addr);
    return retval;    


}

}// namespace ns3